//////////////////////////////////////////////////////////////////////
//!\file MainWindow.cpp
//!\brief Main Application.
//!\author timmsusa@googlemail.com
//////////////////////////////////////////////////////////////////////


#include "MainWindow.hpp"
#include <QApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSplitter>
#include <QMenu>
#include <QMenuBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QDesktopWidget>
#include <QHeaderView>
#include <QPushButton>
#include <QItemSelectionModel>

MainWindow::MainWindow( QWidget *parent ) :
    QMainWindow( parent ),
    m_Persistence(),
    m_FileSystemManager(),
    m_FSModel(),
    m_table(),
    m_fileInfo(),
    m_fileInfoList(),
    m_TreeUpdateView(),
    m_UpdateModel(),
    m_ConfigDialog(),
    m_Tree(),
    m_pUpdateTreeCtxMenu(),
    m_MusicCollectionPath(QDir::homePath()),
    m_FileIncomingPath(QDir::homePath()),
    m_isFile(false),
    m_TableRow(0),
    m_TableColoumn(0),
    m_WizzardEnabled(m_Persistence.getEnableWizard()),
    m_DeepScanEnabled(m_Persistence.getEnableDeepScan())
{

    // Read persisted Filepath
    readPersistedFilePath();

    // Create and configure GUI
    createMainGui();

    // In order to decouple GUI from Filesystemmanager activities
    // we have to create a seaparate thread.
    createFileSystemManagerThread();

    // Either we have remembered a valid, last set collection path and do a search,
    // or we prompt a msgbox for the user to set the path.
    handleStartBehaviour();
}


MainWindow::~MainWindow()
{
    // DTOR
    quitFileSystemManagerThread();
}

void MainWindow::createMainGui()
{
    qDebug() << "MainWindow::createMainGui";

    // Create Main Window
    setWindowTitle( QString::fromUtf8( "flacshlonz" ) );
    QWidget *mainWidget = new QWidget;
    setCentralWidget(mainWidget);

    QVBoxLayout *hMainLayout = new QVBoxLayout;
    QSplitter *midSplitter = new QSplitter(this);
    hMainLayout->addWidget(midSplitter);
    QHBoxLayout *hBottomLayout = new QHBoxLayout;
    hMainLayout->addLayout(hBottomLayout);
    mainWidget->setLayout(hMainLayout);

    // Create Menu Bar
    QMenuBar* menuBar = new QMenuBar(this);
    setMenuBar( menuBar );

    // Sub Menu
    QMenu *fileMenu = new QMenu( QString::fromUtf8( "&Do" ) );
    QMenu *aboutMenu = new QMenu( QString::fromUtf8( "&About" ) );
    QMenu *settingsMenu = new QMenu( QString::fromUtf8( "&Settings" ) );
    menuBar->addMenu( fileMenu );
    menuBar->addMenu( settingsMenu );
    menuBar->addMenu( aboutMenu );

    // Create action
    QAction *setCollectionPathAction = new QAction( QString::fromUtf8( "&Select Music-Library Path" ), fileMenu );
    QAction *setFileIncomingPathAction = new QAction( QString::fromUtf8( "&Select Incoming Files Path" ), fileMenu );
    //QAction *compareAction = new QAction( QString::fromUtf8( "&Compare" ), fileMenu );
    QAction *stopAllSearchAction = new QAction( QString::fromUtf8( "&Stop All Search"), fileMenu );
    QAction *quitAction = new QAction( QString::fromUtf8( "&Quit" ), fileMenu );
    QAction *aboutAction = new QAction( QString::fromUtf8( "&About" ), aboutMenu );

    // Connect action
    QObject::connect( setCollectionPathAction, SIGNAL( triggered() ),
                      this, SLOT( onSetMusicCollectionPath() ) );

    QObject::connect( setFileIncomingPathAction, SIGNAL( triggered() ),
                      this, SLOT( onSetFileIncomingPath() ) );

    //    QObject::connect( compareAction, SIGNAL( triggered() ),
    //                      this, SLOT( onShowUpdateFolderTree() ) );

    QObject::connect( stopAllSearchAction, SIGNAL(triggered() ), this, SIGNAL(sigStopAllSearch()) );
    QObject::connect( quitAction, SIGNAL( triggered() ),
                      qApp, SLOT( quit() ) );

    // Add action
    fileMenu->addAction( setCollectionPathAction );
    fileMenu->addAction( setFileIncomingPathAction );

    //   fileMenu->addAction( compareAction );
    fileMenu->addAction( stopAllSearchAction );
    fileMenu->addAction( quitAction );
    aboutMenu->addAction( aboutAction );


    // Add action: Settings Menu
    QAction *settingsAction = new QAction( QString::fromUtf8("&Settings"), settingsMenu );
    // connect
    connect(settingsAction, SIGNAL(triggered()), this, SLOT(onShowSettingsMenu()));
    settingsMenu->addAction( settingsAction );

    // Logo
    QPixmap *pixmap = new QPixmap( QString::fromUtf8( ":/logo_3.png" ) );
    // Button
    QPushButton *aboutDialog = new QPushButton( *pixmap, QString() );
    aboutDialog->resize( QApplication::desktop()->screenGeometry().size() );
    aboutDialog->setAutoFillBackground( true );
    aboutDialog->setFlat( true );
    aboutDialog->setIconSize( pixmap->size() );
    aboutDialog->setPalette( QPalette( Qt::black ) );
    aboutDialog->setWindowModality( Qt::ApplicationModal );
    aboutDialog->setWindowFlags( Qt::FramelessWindowHint );
    aboutDialog->setWindowFlags( Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint );

    // Connect about-dialogue to action
    QObject::connect( aboutAction, SIGNAL( triggered() ),
                      aboutDialog, SLOT( showMaximized() ) );

    QObject::connect( aboutDialog, SIGNAL( clicked() ),
                      aboutDialog, SLOT( hide() ) );

    // Initialize File-Tree
    m_FSModel.init(QDir::homePath());
    m_Tree = new QTreeView(this);
    m_Tree->setContextMenuPolicy(Qt::CustomContextMenu);
    m_Tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
    m_Tree->setModel( &m_FSModel );
    m_Tree->expandToDepth(1);
    m_Tree->hideColumn( 1 );
    m_Tree->hideColumn( 2 );
    m_Tree->hideColumn( 3 );

    // If tree is clicked, setData to table.
    QObject::connect( m_Tree, SIGNAL( clicked( const QModelIndex & ) ),
                      this, SLOT( onClickedData( const QModelIndex & ) ) );

    QObject::connect( m_Tree, SIGNAL( doubleClicked( QModelIndex ) ),
                      this, SLOT( onDblClickedData( QModelIndex ) ) );

    // If tree is clicked, show Context Menu.
    QObject::connect( m_Tree, SIGNAL( customContextMenuRequested(QPoint) ),
                      this, SLOT( onCollectionTreeCtxMenu( QPoint ) ) );

    midSplitter->addWidget(m_Tree);

    // Table
    m_table = new QTableWidget(this);
    m_table->setAcceptDrops( false );
    m_table->setDragEnabled( false );
    m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_table->setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );
    m_table->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );

    midSplitter->addWidget(m_table);

    m_UpdateModel = new QStandardItemModel(0,0, this);
    m_UpdateModel->setHorizontalHeaderLabels(QStringList("File Incomings..."));

    // Tree Update View
    m_TreeUpdateView = new QTreeView(this);
    m_TreeUpdateView->setContextMenuPolicy(Qt::CustomContextMenu);
    m_TreeUpdateView->setSelectionMode(QAbstractItemView::ContiguousSelection);
    QObject::connect(m_TreeUpdateView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onTreeUpdateCtxMenu(QPoint)));
    QObject::connect(m_TreeUpdateView, SIGNAL(clicked(QModelIndex)), this, SLOT(onUpdateTreeClickedIdx(QModelIndex)));
    QObject::connect(m_TreeUpdateView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onUpdateTreeDblClicked(QModelIndex)));
    midSplitter->addWidget(m_TreeUpdateView);
    m_pStatusBar = new StatusBar;
    m_pStatusBar->setMinimumHeight(height() / 25);
    m_pStatusBar->setMaximumHeight(height() / 25);
    hBottomLayout->addWidget(m_pStatusBar);

    // Context Menu for MusicCollection View
    m_pCollectionCtxMenu = new QMenu(this);
    //m_pCtxMenu->addAction(QString("Copy to..."), this, SLOT(slotTest()));

    m_pCollectionCtxMenu->addAction(QString("Go into"), this, SLOT(slotSetItemToCollectionRootPath()));
    m_pCollectionCtxMenu->addAction(QString("Go back"), this, SLOT(slotGoToLastCollectionRootPath()));
    m_pCollectionCtxMenu->addAction(QString("Remove"), this, SLOT(slotRemoveFromCollection()));
    m_pCollectionCtxMenu->hide();

    // Context Menu for Update Tree view
    m_pUpdateTreeCtxMenu = new QMenu(this);
    //m_pCtxMenu->addAction(QString("Copy to..."), this, SLOT(slotTest()));
    m_pUpdateTreeCtxMenu->addAction(QString("Import to Music-Collection."), this, SLOT(slotCopyToMusicCollection()));
    m_pUpdateTreeCtxMenu->addAction(QString("Import all Folders to Music-Collection."), this, SLOT(slotCopyAllToMusicCollection()));
    m_pUpdateTreeCtxMenu->hide();

    connect(this, SIGNAL(sigRescanAll()), this, SLOT(slotRescanAll()));
    connect(&m_ConfigDialog, SIGNAL(sigEnableWizard(bool)), this, SLOT(slotEnableWizard(bool)));
    connect(&m_ConfigDialog, SIGNAL(sigEnableDeepScan(bool)), this, SLOT(slotEnableDeepScan(bool)));
    connect(this, SIGNAL(sigRunSelectCollectionPathMsgBox()), this, SLOT(slotRunSelectCollectionPathMsgBox()));
}

// Decouples GUI from FS Manager activities.
void MainWindow::createFileSystemManagerThread()
{
    // Create a thread for tts-wrapper.
    QThread* pFileSystemManagerThread = new QThread(this);
    pFileSystemManagerThread->setObjectName("pFlacSearchThread");

    // Put it into, which is only possible, because of deriving from QObject.
    m_FileSystemManager.moveToThread(pFileSystemManagerThread);

    // Connect signal to slot.
    connect(this, SIGNAL(sigSearchInMusicCollection(QString)), &m_FileSystemManager, SLOT(slotSearchInMusicCollection(QString)) );
    connect(this, SIGNAL(sigSearchInFileIncoming(QString)), &m_FileSystemManager, SLOT(slotSearchInFileIncoming(QString)));
    connect(this, SIGNAL(sigCompareFlacLists()), &m_FileSystemManager, SLOT(slotCompareFlacLists()));
    connect(this, SIGNAL(sigCopy(bool,QString,QString)), &m_FileSystemManager, SLOT(slotCopy(bool,QString,QString)));
    connect(this, SIGNAL(sigCopyAllFolderTo(QStringList,QStringList)), &m_FileSystemManager, SLOT(slotCopyAllFolderTo(QStringList,QStringList)));
    connect(this, SIGNAL(sigResetFileCounter()), &m_FileSystemManager, SLOT(slotResetFileCounter()));
    connect(this, SIGNAL(sigRemoveDir(QString)), &m_FileSystemManager, SLOT(slotRemoveDir(QString)));
    connect(this, SIGNAL(sigEnableDeepScan(bool)), &m_FileSystemManager, SLOT(slotEnableDeepScan(bool)));
    connect(this, SIGNAL(sigStopAllSearch()), &m_FileSystemManager, SIGNAL(sigStopScanMusicCollection()));
    connect(this, SIGNAL(sigStopAllSearch()), &m_FileSystemManager, SIGNAL(sigStopScanUpdateCollection()));

    // In order to use slots and signals with parameters, we have to use qRegisterMetaType.
    //typedef QVector<Album> tAlbumVec;
    qRegisterMetaType< Album > ( "Album" );
    qRegisterMetaType< QVector< Album > > ( "QVector<Album>" );


    connect(&m_FileSystemManager, SIGNAL(sigFlacFound(QString)), this, SLOT(slotFlacFound(QString)));
    connect(&m_FileSystemManager, SIGNAL(sigFolderFound(Album)), this, SLOT(slotFlacFolderFound(Album)));
    connect(&m_FileSystemManager, SIGNAL(sigSearchInMusicCollectionFinished()), this, SLOT(slotSearchInMusicCollectionFinished()));
    connect(&m_FileSystemManager, SIGNAL(sigSearchInFileIncomingFinished()), this, SLOT(slotSearchInFileIncomingFinished()));
    connect(&m_FileSystemManager, SIGNAL(sigFlacListComparisonFinished(QVector<Album>)), this, SLOT(slotFlacListComparisonFinished(QVector<Album>)));
    connect(&m_FileSystemManager, SIGNAL(sigCopyProgress(int)), this, SLOT(slotCopyProgress(int)));

    // Do we need this line?
    // connect(m_FlacSearcher.thread(), SIGNAL(finished()), m_FlacSearcher.thread(), SLOT(deleteLater()));

    // Start thread.
    pFileSystemManagerThread->start();
}

bool MainWindow::runMsgBoxRemoveSelection()
{
    bool retVal = false;

    // Message Box
    QMessageBox *msgBox = new QMessageBox(this);
    msgBox->setIcon(QMessageBox::Question);
    msgBox->setText("Do you really want to remove your selection?");
    //msgBox->setInformativeText((m_fileInfo.absoluteFilePath() + "...");
    msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox->setDefaultButton(QMessageBox::No);

    int ret = msgBox->exec();
    switch (ret)
    {
    case QMessageBox::Yes:
        qDebug() << "Yes was clicked!";
        retVal = true;
        break;
    case QMessageBox::No:
        retVal = false;
        break;
    default:
        qDebug() << ret << " was clicked... this should never been happen!";
        // should never be reached
        break;
    }

    return retVal;
}

bool MainWindow::runMsgBoxFinishedFlacSearchCollection()
{
    bool retVal = false;

    m_pStatusBar->setLabelTxt("SUCCESS! Your FLAC Music-Collection was tracked. Now, please scan your Incoming-File Folder for new FLAC-Files.");
    QMessageBox *msgBox = new QMessageBox(this);
    msgBox->setIcon(QMessageBox::Question);
    msgBox->setText("SUCCESS! Your FLAC Music-Collection was tracked. Now, please scan your Incoming-File Folder for new FLAC-Files.");
    msgBox->setInformativeText("Would you like to set your Incoming-File-Path, now?");
    msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox->setDefaultButton(QMessageBox::Yes);

    int ret = msgBox->exec();
    switch (ret)
    {
    case QMessageBox::Yes:
        qDebug() << "Yes was clicked!";
        retVal = true;
        emit onSetFileIncomingPath();
        break;
    case QMessageBox::No:
        qDebug() << "No was clicked!";
        retVal = false;
        break;
    default:
        qDebug() << ret << " was clicked... this should never been happen!";
        // should never be reached
        break;
    }
    return retVal;
}

bool MainWindow::runMsgBoxSelectCollectionPath()
{
    bool retVal = false;

    QMessageBox *msgBox = new QMessageBox(this);
    msgBox->setIcon(QMessageBox::Question);
    msgBox->setText("Salve!"); //("Would you like to select the path to your Music-Collection?");
    msgBox->setInformativeText("Would you like to select the path to your Music-Collection, now?");
    msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox->setDefaultButton(QMessageBox::Yes);

    int ret = msgBox->exec();
    switch (ret)
    {
    case QMessageBox::Yes:
        qDebug() << "Yes was clicked!";
        retVal = true;
        emit onSetMusicCollectionPath();
        break;
    case QMessageBox::No:
        qDebug() << "No was clicked!";
        retVal = false;
        break;
    default:
        qDebug() << ret << " was clicked... this should never been happen!";
        // should never be reached
        break;
    }
    return retVal;
}

void MainWindow::setTableLabels(int count)
{
    qDebug() << "MainWindow::setTableLabels " << count;

    m_TableRow=0;
    m_TableColoumn=0;

    m_fileInfoList.clear();

    // Set table labels.
    if(  m_fileInfo.isFile() )
    {
        m_fileInfoList.append( m_fileInfo );
        m_table->setColumnCount( 1 );
        m_table->setRowCount( count );
        QStringList labels;
        labels << "Value";
        m_table->setHorizontalHeaderLabels( labels );
        m_table->setVerticalHeaderLabels( m_metadataKeys.toList() );
    }
    else
    {
        QDir dir(  m_fileInfo.filePath());
        m_fileInfoList = dir.entryInfoList
                (
                    FileSystemModel::s_FileFilter,
                    QDir::Files,
                    QDir::Name
                    );

        m_table->setColumnCount( count );
        m_table->setRowCount( m_fileInfoList.size() );
        qDebug() << "fileinfolist.size is " << m_fileInfoList.size() << "count is" << count;
        m_table->setHorizontalHeaderLabels( m_metadataKeys.toList() );
    }
}

void MainWindow::setTreeViewRoot(const QString& path)
{
    qDebug() << "MainWindow::setTreeViewRoot " << path;
    m_FSModel.setHeaderTxt(path);
    m_Tree->setRootIndex(m_FSModel.index(path));
}

void MainWindow::fillMetavalueTable()
{
    qDebug() << "MainWindow::fillMetavalueTable";

    m_isFile =  m_fileInfo.isFile();

    // Flush table on screen.
    m_table->clear();

    // Create Metadata Container
    QVector< QString > metadataValues( m_metadataKeys.size(), "" );

    // Create dimensions.
    setTableLabels(metadataValues.size());

    // Fill with table values and paint to table.
    traverseFileInfoList(metadataValues);

    // Resize
    m_table->resizeColumnsToContents();
    m_table->resizeRowsToContents();

    QHeaderView *headerView = m_table->horizontalHeader();
    headerView->setStretchLastSection( true );

}

// Be shure to check if table or couloumn row must be reset beforehand!
void MainWindow::putFlacMetaDataToTable(const QVector<QString> & metadataValues, bool isFile)
{
    qDebug() << "MainWindow::putFlacMetaDataToTable";

    // Paint values to table.
    for( int i = 0; i < metadataValues.size(); i++ )
    {
        QTableWidgetItem *newItem = new QTableWidgetItem( metadataValues.at( i ) );

        m_table->setItem( m_TableRow, m_TableColoumn, newItem );

        if( isFile )
        {
            m_TableRow++;
        }
        else
        {
            m_TableColoumn++;
        }
    }
}

void MainWindow::onSetMusicCollectionPath()
{
    m_MusicCollectionPath = QFileDialog::getExistingDirectory(this, tr("Open Folder"), m_MusicCollectionPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    qDebug() << "Your Music Collection Folder is: " << m_MusicCollectionPath << "\n";

    if (m_MusicCollectionPath.isEmpty())
    {
        qDebug() << "Path is empty";
    }
    else
    {
        m_Persistence.persistLastOpenCollectionPath(m_MusicCollectionPath);

        // Reset Tree-View
        setTreeViewRoot(m_MusicCollectionPath);

        emit sigSearchInMusicCollection(m_MusicCollectionPath);
    }
}

void MainWindow::onSetFileIncomingPath()
{
    // Clear old results.
    clearUpdateView();

    m_FileIncomingPath = QFileDialog::getExistingDirectory(this, tr("Open Folder"), m_FileIncomingPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    qDebug() << "Your Incoming Files Folder is: " << m_FileIncomingPath << "\n";
    if (m_FileIncomingPath.isEmpty())
    {
        qDebug() << "Path is empty";
    }
    else
    {
        emit sigSearchInFileIncoming(m_FileIncomingPath); // Will send finished signal!
    }
}

void MainWindow::onShowSettingsMenu()
{
    qDebug() << "MainWindow::onShowSettingsMenu";
    m_ConfigDialog.show();
}

void MainWindow::onShowUpdateFolderTree(const QVector < Album >& list)
{
    qDebug() << "MainWindow::onShowUpdateFolderTree";

    // Clean up view and model
    if ( m_UpdateModel->hasIndex(0,0))
    {
        m_UpdateModel->clear();
        m_TreeUpdateView->setModel(m_UpdateModel);
    }

    // Print if no new files were found!
    if (list.empty())
    {
        //m_table->clear();
        //m_UpdateModel->clear();
        QMessageBox *mb = new QMessageBox;
        mb->setText("No FLAC-Files for update found!");
        mb->show();
        return;
    }
    else
    {
        m_UpdateModel->setHorizontalHeaderLabels(QStringList(m_FileIncomingPath));

        // Crop piece of path, because its part of m_Fileincoming.
        //QString lastDir = m_FlacFSManager.getUpdateTrackList().first().m_File.absolutePath().remove(0,m_FileIncomingPath.length());//.front().m_File.absoluteDir().dirName();

        if (list.empty())
            return;

        QString lastDir = list.constBegin()->getPath().remove(0,m_FileIncomingPath.length());
        QStandardItem *parentItem = m_UpdateModel->invisibleRootItem();
        QStandardItem *item = new QStandardItem(lastDir);
        parentItem->appendRow(item);
        parentItem=item;

        for( QVector < Album >::const_iterator uit = list.begin(); uit != list.end(); ++uit )
        {
            Album album = *uit;
            QString foundPath = album.getPath().remove(0,m_FileIncomingPath.length());
            if ( lastDir != foundPath)
            {
                // Tree View Update
                parentItem = m_UpdateModel->invisibleRootItem();
                // QString foundPath = updateTrack.m_File.absolutePath().remove(0,m_FileIncomingPath.length());
                item = new QStandardItem(foundPath);
                item->setWhatsThis(foundPath);
                parentItem->appendRow(item);
                parentItem=item;

                lastDir = foundPath;
            }
            albumTracksToUpdateTreeView(album, parentItem);
        }


        /*
        for( QVector < FlacTrack >::const_iterator uit = m_FlacFSManager.getUpdateTrackList().begin(); uit != m_FlacFSManager.getUpdateTrackList().end(); ++uit )
        {
            FlacTrack updateTrack = *uit;
            QString foundPath = updateTrack.m_File.absolutePath().remove(0,m_FileIncomingPath.length());
            if ( lastDir != foundPath)
            {
                // Tree View Update
                parentItem = m_UpdateModel->invisibleRootItem();
               // QString foundPath = updateTrack.m_File.absolutePath().remove(0,m_FileIncomingPath.length());
                QStandardItem *item = new QStandardItem(foundPath);
                item->setWhatsThis(updateTrack.m_File.absolutePath());
                parentItem->appendRow(item);
                parentItem=item;

                lastDir = foundPath;
            }
            // Tree View update
            QStandardItem *trackItem = new QStandardItem(updateTrack.m_File.fileName());
            parentItem->appendRow(trackItem);

        }
*/
        m_TreeUpdateView->setModel(m_UpdateModel);
    }
}


// Scans and fills m_table with flac metadata information.
void MainWindow::onClickedData( const QModelIndex & index )
{
    qDebug() << "MainWindow::onClickedData";

    m_fileInfo = QFileInfo(m_FSModel.fileInfo(index));
    fillMetavalueTable();
}

void MainWindow::onDblClickedData( const QModelIndex & index )
{
    qDebug() << "MainWindow::onDblClickedData";

    m_fileInfo = QFileInfo(m_FSModel.fileInfo(index));
    QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileInfo.absoluteFilePath()));
    fillMetavalueTable();

}

void MainWindow::onCollectionTreeCtxMenu( QPoint )
{
    qDebug() << "MainWindow::onCollectionTreeCtxMenu";
    m_pCollectionCtxMenu->show();
    m_pCollectionCtxMenu->exec(QCursor::pos());
}

void MainWindow::onUpdateTreeClickedIdx(QModelIndex idx)
{
    qDebug() << "MainWindow::onUpdateTreeClickedIdx" << idx.column() << idx.row();

    m_fileInfo = getFileInfoByUpdateTreeModelIdx(idx);

    fillMetavalueTable();
}

// Will open folders or files by OS set application.
void MainWindow::onUpdateTreeDblClicked(QModelIndex idx)
{

    m_fileInfo = getFileInfoByUpdateTreeModelIdx(idx);

    // EXP
    QDesktopServices::openUrl(QUrl::fromLocalFile(m_fileInfo.absoluteFilePath()));
}

void MainWindow::onTreeUpdateCtxMenu(QPoint)
{
    qDebug() << "MainWindow::onTreeUpdateCtxMenu(QPoint)";
    m_pUpdateTreeCtxMenu->show();
    m_pUpdateTreeCtxMenu->exec(QCursor::pos());
}

void MainWindow::slotFlacFound(QString file)
{
    if ( NULL != m_pStatusBar )
    {
        m_pStatusBar->setLabelTxt(file);
    }
}

void MainWindow::slotSearchInMusicCollectionFinished()
{
    qDebug() << "MainWindow::slotSearchInMusicCollectionFinished";
    m_pStatusBar->setLabelTxt("Searching in Music-Collection successfully finished.");

    if (m_WizzardEnabled)
    {
        if ( !runMsgBoxFinishedFlacSearchCollection() )
        {
            return;
        }
    }
}
void MainWindow::slotSearchInFileIncomingFinished()
{
    qDebug() << "MainWindow::slotSearchInFileIncomingFinished";
    m_pStatusBar->setLabelTxt("Searching in File-Incoming Folder successfully finished.");
    m_WizzardEnabled = false;
    emit sigCompareFlacLists();
}

void MainWindow::slotFlacListComparisonFinished(QVector < Album > list)
{
    qDebug() << "MainWindow::slotFlacListComparisonFinished";
    if (list.empty())
    {
        qDebug() << "list is empty!!";
        m_pStatusBar->setLabelTxt("Comparison failed!");
        return;
    }
    else
    {
        m_pStatusBar->setLabelTxt("Comparison finished!");
    }
    emit onShowUpdateFolderTree(list);

}

void MainWindow::slotCopyToMusicCollection()
{
    qDebug() << "MainWindow::slotCopyToMusicCollection";


    m_pStatusBar->showProgressBar();
    copySelectionFromUpdateCollection();
}

void MainWindow::slotCopyAllToMusicCollection()
{
    qDebug() << "MainWindow::slotCopyAllToMusicCollection";


    QStringList srcList;
    QStringList destList;
    int i = 0;

    emit sigResetFileCounter();
    m_pStatusBar->showProgressBar();

    /*
    QVector< Album >::const_iterator it;
    for(it = list.begin(); it != list.end(); ++it)
    {
        qDebug() << it->getPath();
        srcList.push_back(it->getPath());
        destList.push_back(m_MusicCollectionPath + "//" + it->getName());
    }
    */
    while ( m_UpdateModel->hasIndex(i,0) )
    {
        QString  str = m_UpdateModel->item(i, 0)->text();
        QFileInfo *fi = new QFileInfo(m_FileIncomingPath + "//" + str);
        QStringList slashParts = fi->absoluteFilePath().split("/");
        QString dest = m_MusicCollectionPath + "//" +  slashParts.last();
        qDebug() << "source: " << fi->absoluteFilePath() << " destination: " << dest;
        srcList.push_back(fi->absoluteFilePath());
        destList.push_back(dest);
        i++;
    }

    if (srcList.isEmpty())
    {
        qDebug() << "Sourcelist is empty";
        m_pStatusBar->hideProgressBar();
        return;
    }

    emit sigCopyAllFolderTo(srcList, destList);

    // After copy request, clear all item data in update tree view
    // TO DO: Make it cool, and retrigger GUI.
    m_UpdateModel->clear();
    m_TreeUpdateView->setModel(m_UpdateModel);
}

void MainWindow::slotCopyProgress(int perc)
{

    if (perc > -1)
    {
        m_pStatusBar->setProgressBar(perc);
        QString tmp = "Copying: " + QString::number(perc) + " / " + QString::number(m_pStatusBar->getProgressBarMax());
        m_pStatusBar->setLabelTxt( tmp );
    }

    // TO DO: Make it cool
    if (perc == m_pStatusBar->getProgressBarMax())
    {
        m_pStatusBar->hideProgressBar();
        m_pStatusBar->setLabelTxt("Copy finished!");

        removeSelectedUpdateItems();

        qDebug() << "MainWindow::slotCopyFinished";

        // TODO: uncool, but: if more than one was copied, do a rescan!
        if (m_pStatusBar->getProgressBarMax() > 2)
        {
            emit sigRescanAll();
        }
        m_pStatusBar->hideProgressBar();
    }

    if (perc == -1)
    {
        m_pStatusBar->hideProgressBar();
        m_pStatusBar->setLabelTxt("Nothing was copied!");
        QMessageBox *box = new QMessageBox;
        box->setText("Nothing was copied! Maybe, your file already exists?");
        box->show();
    }
}

void MainWindow::slotRemoveFromCollection()
{
    qDebug() << "MainWindow::slotRemoveFromCollection" << m_fileInfo.absoluteFilePath();

    if (!runMsgBoxRemoveSelection())
    {
        return;
    }

    // Remove selection
    removeSelectionFromCollection();
}

void MainWindow::slotRescanAll()
{
    m_pStatusBar->setLabelTxt("Rescanning...");
    emit sigSearchInMusicCollection(m_MusicCollectionPath);
    emit sigSearchInFileIncoming(m_FileIncomingPath);
    m_pStatusBar->setLabelTxt("Rescan finished.");
}

void MainWindow::slotSetItemToCollectionRootPath()
{
    qDebug() << "MainWindow::slotSetItemToCollectionRootPath";

    // Remember!
    m_CollectionPathHistory.push_back(m_MusicCollectionPath);
    // Get path from file info
    m_MusicCollectionPath = m_fileInfo.absolutePath();
    // Persist.
    m_Persistence.persistLastOpenCollectionPath(m_MusicCollectionPath);

    // Reset Tree-View
    setTreeViewRoot(m_MusicCollectionPath);
    emit sigSearchInMusicCollection(m_MusicCollectionPath);
    //emit sigRescanAll();
}

void MainWindow::slotGoToLastCollectionRootPath()
{
    qDebug() << "MainWindow::slotGoToLastCollectionRootPath";

    if (m_CollectionPathHistory.last().isEmpty())
        return;

    QString lastPath = m_CollectionPathHistory.last();
    m_CollectionPathHistory.removeLast();

    if (m_MusicCollectionPath == lastPath)
        return;

    m_MusicCollectionPath = lastPath;
    m_Persistence.persistLastOpenCollectionPath(m_MusicCollectionPath);
    setTreeViewRoot(m_MusicCollectionPath);
   // emit sigRescanAll();
    emit sigSearchInMusicCollection(m_MusicCollectionPath);
}

void MainWindow::slotEnableWizard(bool enable)
{
    qDebug() << "MainWindow::slotEnableWizard " << enable;
    m_WizzardEnabled = enable;
}

void MainWindow::slotEnableDeepScan(bool enable)
{
    qDebug() << "MainWindow::slotEnableDeepScan " << enable;
    m_DeepScanEnabled = enable;
    emit sigEnableDeepScan(enable);
}

void MainWindow::slotFlacFolderFound(Album album)
{
    qDebug() << "MainWindow::slotFlacFolderFound " << album.getName();
    //albumTracksToUpdateTreeView(album, m_UpdateModel->invisibleRootItem());
    //m_TreeUpdateView->setModel(m_UpdateModel);
}

void MainWindow::slotRunSelectCollectionPathMsgBox()
{
    runMsgBoxSelectCollectionPath();
}

void MainWindow::traverseFileInfoList(QVector< QString >& metadataValues)
{
    qDebug() << "MainWindow::traverseFileInfoList";

    // Set values.
    for( QFileInfoList::const_iterator it = m_fileInfoList.constBegin(); it != m_fileInfoList.constEnd(); it++ )
    {
        QString fileName( it->fileName() );
        QString filePath( it->filePath() );
        //qDebug() << "\nfilename: " << filePath << "\n";
        metadataValues[ m_lut[ m_fileHdrLabel ] ] = fileName;
        FlacMetadataManager::fileInfoToMetaData(metadataValues,  m_fileInfo.isFile(), filePath);

        // Paint values to table.
        putFlacMetaDataToTable(metadataValues,  m_fileInfo.isFile());
    }
}

// Returns a list of selected items in music collection model
QFileInfoList MainWindow::getSelectionListFromCollection()const
{
    QModelIndexList mil = m_Tree->selectionModel()->selectedIndexes();
    QFileInfoList fil;//= new QFileInfoList;

    foreach (const QModelIndex& it, mil)
    {
        QFileInfo fi(m_FSModel.fileInfo(it));
        fil.push_back(fi);
    }
    return fil;
}

void MainWindow::removeFromCollectionFileSystem()
{
    if ( m_fileInfo.isFile() )
    {
        QFile::remove(m_fileInfo.absoluteFilePath());
    }
    else
    {
        emit sigRemoveDir(m_fileInfo.absoluteFilePath());
        //emit sigSearchInMusicCollection(m_MusicCollectionPath);
        //emit sigRescanAll();
    }
}

void MainWindow::removeSelectionFromCollection()
{

    // Remove selection
    QFileInfoList list = getSelectionListFromCollection();
    foreach (const QFileInfo lfi, list)
    {
        m_fileInfo = lfi;
        m_isFile = lfi.isFile();
        qDebug() << "removing... " << lfi.absoluteFilePath();
        removeFromCollectionFileSystem();
    }

}

void MainWindow::copySelectionFromUpdateCollection()
{

    // copy selection
    QModelIndexList list = m_TreeUpdateView->selectionModel()->selectedIndexes();
    m_UpdateTreeViewModelIdxList = list;
    QStringList srcList;
    QStringList destList;
    int fileCount=0;

    foreach (const QModelIndex& idx, list)
    {
        m_UpdateTreeViewModelIdx = idx;
        QFileInfo fi(getFileInfoByUpdateTreeModelIdx(idx));

        // Count Files for progressbar
        if(!fi.absoluteFilePath().endsWith(".flac"))
        {
            fileCount = fileCount + QDir(fi.absoluteFilePath()).entryList(QDir::Files).size();
        }
        else
        {
            fileCount = fileCount + 1;
        }

        QStringList dotParts = fi.absoluteFilePath().split("/");
        QString dotPart = dotParts.last();
        QString tmp = m_MusicCollectionPath + "//" + dotPart;
        if ( !dotPart.isEmpty() )
        {
            destList.push_back(tmp);
            srcList.push_back(fi.absoluteFilePath());
        }
    }
    emit sigResetFileCounter();
    m_pStatusBar->setProgressBarMax(fileCount);

    emit sigCopyAllFolderTo(srcList, destList);
}

const QFileInfo& MainWindow::getFileInfoByUpdateTreeModelIdx(const QModelIndex& idx)
{
    QString curFolder;
    QString curFile;

    m_UpdateTreeViewModelIdx = idx;

    if (idx.parent().isValid())
    {
        curFolder = m_FileIncomingPath + idx.parent().data().toString();
        curFile = idx.data().toString();
        m_pStatusBar->setLabelTxt("File Clicked! Current Folder: " + curFolder + " and File: " + curFile);
        m_isFile = true;

    }
    else
    {
        curFolder = m_FileIncomingPath + idx.data().toString();
        m_pStatusBar->setLabelTxt("Folder clicked! Current Folder: " + curFolder);
        m_isFile = false;
    }

    QString sumPath = (curFile.isEmpty()) ? curFolder : (curFolder + "//" + curFile);
    QFileInfo *fi = new QFileInfo(sumPath);
    qDebug() << sumPath;
    return *fi;
}

void MainWindow::removeSelectedUpdateItems()
{

    // This approach fails for removing selected child items, why?
    foreach(const QModelIndex& idx, m_TreeUpdateView->selectionModel()->selectedIndexes())
    {
        if (idx.parent().isValid())
        {

            m_UpdateModel->removeRow(idx.row(), idx.parent());
            qDebug() << "isValid " << idx.data().toString();
        }
        else
        {
            //
            m_UpdateModel->removeRow(idx.row());
            m_TreeUpdateView->update();
            qDebug() << "notValid";
        }
    }

    /*
    if( m_TreeUpdateView->selectionModel()->hasSelection() ) {  // check if there are selections?
       // there are selections
       // QTreeView also contains api's to work with selected indexes, although convenient, this would cause a problem
       // because selectedIndexes is unsorted - meaning updated as user selects items and can be random
       // foreach( QModelIndex index, treeView->selectedIndexes() ) {
       //    model->takeRow( index.row() );  // QStandardItemModel takeRow( int row )
       // }
       //
       // In the above scenario if you had rows 1,2,3,4,5  and rows 2,4 were selected for deletion,
      //  then rows 2 and 5 would be deleted.  Because once you deleted 2, row 5 now becomes row 4 (in model).
      //  So you need to ensure you work from the bottom up when deleting rows from a QTreeView.
      //  Something Like:

      // Capture all rows to be deleted by it's row number in list
      QList<int> rowList;
      foreach( QModelIndex index, m_TreeUpdateView->selectionModel()->selectedIndexes() )
      {
          rowList << index.row();
      }
      // Use QtAlgorithm qSort to reverse sort row numbers in list
      qSort( rowList.begin(), rowList.end(), qGreater<int>() );  // reverse sort 5,4,3,...

      // Perform deletions - model updates will update tree view.
      foreach( int row, rowList )
      {
          m_UpdateModel->takeRow( row );  // QStandardItemModel takeRow( int row )
      }
    }

*/
}

void MainWindow::albumTracksToUpdateTreeView(const Album &album, QStandardItem *parentItem)
{

    // Set child items to parent
    if (!m_DeepScanEnabled)
    {
        if (!(album.getTrackList().empty()))
        {
            foreach(const QString& track, album.getTrackList())
            {
                QStandardItem *trackItem = new QStandardItem(track);
                parentItem->appendRow(trackItem);
            }
        }
        else
        {
            qDebug() << "Tracklist is empty!";
        }
    }
    else
    {
        if ( !album.getFlacTrackList().empty() )
        {
            foreach(const FlacTrack& flacTrack, album.getFlacTrackList() )
            {
                QStandardItem *trackItem=new QStandardItem(flacTrack.m_File);
                parentItem->appendRow(trackItem);
            }
        }
        else
        {
            qDebug() << "Flactracklist is empty!";
        }
    }
}

// Should clear out all content from update view.
void MainWindow::clearUpdateView()
{
    m_TreeUpdateView->reset();
    m_UpdateModel->clear();
}

void MainWindow::readPersistedFilePath()
{
    if ( m_Persistence.getLastOpenCollectionPathEnabled())
        m_MusicCollectionPath = m_Persistence.getLastOpenCollectionPath();
    else
        m_MusicCollectionPath.clear();// = QDir::rootPath();
}

// Either we have remembered a valid, last set collection path and do a search,
// or we prompt a msgbox for the user to set the path.
void MainWindow::handleStartBehaviour()
{
    if(QDir(m_MusicCollectionPath).exists() && !m_MusicCollectionPath.isEmpty())
    {
        emit sigSearchInMusicCollection(m_MusicCollectionPath);
        setTreeViewRoot(m_MusicCollectionPath);
    }
    else
    {
        m_pStatusBar->setLabelTxt("Please chose your Music collection path!");
        if (m_Persistence.getEnableWizard())
        {
            emit sigRunSelectCollectionPathMsgBox();
        }
    }
}

void MainWindow::quitFileSystemManagerThread()
{
    m_FileSystemManager.thread()->quit();
}
